use crate::common::rdius::ChatRedis;
use crate::common::utils::parse_utils::parse_usize;
use crate::common::utils::time_utils::{get_time_format, group_item_by_time};
use crate::service::model::chat_handler_model::{PostBean, WsRequest, WsResponse};
use crate::service::model::chat_model::{BaseChatValueBean, ChatUser, Message, MessageList};
use crate::service::server::chat::ChatServer;
use crate::service::server::chat_session::ChatSession;
use crate::service::webrtc::webrtc::WebrtcServer;
use crate::service::webrtc::webrtc_session::WebrtcSession;
use crate::sql::chat::{
    get_message, get_message_list_by_receive_sql, get_message_list_sql, get_message_more_sql,
    get_user_info_list,
};
use actix::Addr;
use actix_web::rt::time::Instant;
use actix_web::web::post;
use actix_web::{get, web, Error, HttpRequest, HttpResponse};
use actix_web_actors::ws;
use chrono::{Local, NaiveDateTime};
use sqlx::{Pool, Postgres};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashMap;

#[get("/webrtc/{id}")]
pub async fn webrtc(
    _req: HttpRequest,
    _stream: web::Payload,
    addr: web::Data<Addr<WebrtcServer>>,
) -> Result<HttpResponse, Error> {
    let id = parse_usize(_req.match_info().get("id").unwrap()).unwrap();
    println!("id:{:?}", id);
    ws::start(
        WebrtcSession {
            id,
            addr: addr.get_ref().clone(),
        },
        &_req,
        _stream,
    )
}

#[get("/ws/{id}")]
pub async fn websocket(
    _req: HttpRequest,
    _stream: web::Payload,
    addr: web::Data<Addr<ChatServer>>,
) -> Result<HttpResponse, Error> {
    let id = parse_usize(_req.match_info().get("id").unwrap()).unwrap();
    let info = HashMap::new();
    ws::start(
        ChatSession {
            id,
            info,
            hb: Instant::now(),
            addr: addr.get_ref().clone(),
        },
        &_req,
        _stream,
    )
}

pub const CHAT_LIST: &str = "chat_list";
pub const CHAT: &str = "chat";
pub const CHAT_OPEN: &str = "chat_open";
pub const CHAT_READ: &str = "chat_read";
pub const CHAT_MORE: &str = "chat_more";
pub const CHAT_USERS: &str = "chat_users";
pub const CHAT_RTC: &str = "chat_rtc";

pub async fn ws_request(
    pool: &Pool<Postgres>,
    redis: &mut ChatRedis,
    id: usize,
    _msg: String,
) -> Result<Vec<WsResponse>, Error> {
    let mut ws_request: PostBean = serde_json::from_str(&_msg)?;

    let mut vec = Vec::new();
    let mold: &str = &ws_request.mold;
    match mold {
        CHAT_LIST => {
            let result = ws_chat_list(pool, redis, id, &ws_request).await.unwrap();
            ws_request.value = result;

            vec.insert(
                0,
                WsResponse {
                    id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT_OPEN => {
            let result = ws_chat_room_message(pool, redis, id, &ws_request)
                .await
                .unwrap();
            ws_request.value = result;
            vec.insert(
                0,
                WsResponse {
                    id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT_MORE => {
            let result = ws_chat_message_more(pool, id, &ws_request).await.unwrap();
            ws_request.value = result;
            vec.insert(
                0,
                WsResponse {
                    id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT_READ => {
            ws_chat_read(pool, redis, id, &ws_request).await;
            let receive_id = ws_request.id;
            ws_request.id = id;
            vec.insert(
                0,
                WsResponse {
                    id: receive_id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT_USERS => {
            let result = chat_users(pool, id, &ws_request).await.unwrap();
            ws_request.value = result;

            vec.insert(
                0,
                WsResponse {
                    id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT_RTC => {
            let receive_id = ws_request.id;
            ws_request.id = id;

            vec.insert(
                0,
                WsResponse {
                    id: receive_id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        CHAT => {
            ws_chat(pool, redis, id, &ws_request).await;
            let receive_id = ws_request.id;
            ws_request.id = id;
            vec.insert(
                0,
                WsResponse {
                    id: receive_id,
                    text: serde_json::to_string(&ws_request).unwrap(),
                },
            );
        }
        _ => {}
    };

    if vec.len() == 0 {
        vec.insert(0, WsResponse { id, text: _msg });
    }

    Ok(vec)
}

pub async fn chat_users(
    pool: &Pool<Postgres>,
    id: usize,
    post_bean: &PostBean,
) -> Result<String, Error> {
    let result = get_user_info_list(pool, id).await.unwrap();
    Ok(serde_json::to_string(&BaseChatValueBean { data: result }).unwrap())
}

pub async fn ws_chat_read(
    pool: &Pool<Postgres>,
    redis: &mut ChatRedis,
    id: usize,
    post_bean: &PostBean,
) {
    redis.message_list_read(pool, post_bean.id, id).await;
}

pub async fn ws_chat(
    pool: &Pool<Postgres>,
    redis: &mut ChatRedis,
    id: usize,
    post_bean: &PostBean,
) {
    let send_id = id as i32;
    let receive_id = post_bean.id as i32;

    let now = Local::now()
        .naive_local()
        .format("%Y-%m-%d %H:%M:%S")
        .to_string();

    redis.add_message(Message {
        id: 0,
        user_id: send_id,
        value: post_bean.value.clone(),
        mold: 1,
        is_read: 0,
        receive_id,
        create_time: now.clone(),
    });

    redis
        .add_message_list(
            pool,
            0,
            MessageList {
                id: send_id,
                send_id,
                receive_id,
                num: 0,
                last_message: post_bean.value.clone(),
                last_time: now.clone(),
                send_nick: "".to_string(),
                send_logo: "".to_string(),
                receive_nick: "".to_string(),
                receive_logo: "".to_string(),
            },
        )
        .await;
    redis
        .add_message_list(
            pool,
            1,
            MessageList {
                id: send_id,
                receive_id: send_id,
                send_id: receive_id,
                num: 0,
                last_message: post_bean.value.clone(),
                last_time: now.clone(),
                send_nick: "".to_string(),
                send_logo: "".to_string(),
                receive_nick: "".to_string(),
                receive_logo: "".to_string(),
            },
        )
        .await;
}

pub async fn ws_chat_list(
    pool: &Pool<Postgres>,
    redis: &mut ChatRedis,
    id: usize,
    _post_bean: &PostBean,
) -> Result<String, Error> {
    let mut message_receive_list = redis.get_message_list_receive(id);
    let mut message_list_receive_sql = get_message_list_by_receive_sql(pool, id as i32)
        .await
        .unwrap();
    let mut new_message_list_receive = Vec::new();
    //整合message_receive缓存跟数据库结果
    for x in message_list_receive_sql {
        let key = x.send_id as usize;
        if message_receive_list.contains_key(&(key)) {
            new_message_list_receive.insert(0, message_receive_list.remove(&key).unwrap());
        } else {
            new_message_list_receive.insert(0, x);
        }
    }

    for (_, value) in message_receive_list {
        new_message_list_receive.insert(0, value);
    }
    new_message_list_receive.sort_by(|l, r| {
        let left_time = NaiveDateTime::parse_from_str(&l.last_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        let right_time = NaiveDateTime::parse_from_str(&r.last_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        if left_time > right_time {
            return Ordering::Less;
        } else if left_time < right_time {
            return Ordering::Greater;
        }
        return Ordering::Equal;
    });
    let mut data_message_list = Vec::new();
    for mut x in new_message_list_receive {
        // x.last_time = get_time_format(&x.last_time);
        data_message_list.push(x);
    }

    Ok(serde_json::to_string(&BaseChatValueBean {
        data: data_message_list,
    })
    .unwrap())
}

fn new_message(messages: &Vec<Message>) -> Vec<Message> {
    let mut new_messages = Vec::new();
    for x in messages {
        new_messages.push(Message {
            id: x.id,
            user_id: x.user_id,
            value: x.value.clone(),
            mold: x.mold,
            is_read: x.is_read,
            receive_id: x.receive_id,
            create_time: x.create_time.clone(),
        })
    }

    new_messages
}

pub async fn ws_chat_room_message(
    pool: &Pool<Postgres>,
    redis: &mut ChatRedis,
    id: usize,
    post_bean: &PostBean,
) -> Result<String, Error> {
    let receive_id = post_bean.id as i32;
    let send_id = id as i32;
    let empty_vec = Vec::new();
    let mut message = if redis.message.contains_key(&id) {
        new_message(redis.message.get(&id).unwrap())
    } else {
        empty_vec
    };
    let mut receive_message = if redis.message.contains_key(&post_bean.id) {
        new_message(redis.message.get(&post_bean.id).unwrap())
    } else {
        Vec::new()
    };
    let mut message_sql = get_message(pool, send_id, receive_id).await.unwrap();
    let mut new_message = Vec::new();
    for message in message {
        if message.receive_id == receive_id {
            new_message.push(message);
        }
    }
    for message in receive_message {
        if message.receive_id == send_id {
            new_message.push(message);
        }
    }

    new_message.extend(message_sql);

    new_message.sort_by(|l, r| {
        let left_time = NaiveDateTime::parse_from_str(&l.create_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        let right_time = NaiveDateTime::parse_from_str(&r.create_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        if left_time > right_time {
            return Ordering::Greater;
        } else if left_time < right_time {
            return Ordering::Less;
        }
        return Ordering::Equal;
    });

    let group_message = group_item_by_time(new_message);

    let json = serde_json::to_string(&BaseChatValueBean {
        data: group_message,
    });

    Ok(json.unwrap())
}
pub async fn ws_chat_message_more(
    pool: &Pool<Postgres>,
    id: usize,
    post_bean: &PostBean,
) -> Result<String, Error> {
    let more_message = get_message_more_sql(pool, id, post_bean.id, &post_bean.value).await;

    let mut more_message = match more_message {
        Ok(msg) => msg,
        Err(err) => Vec::new(),
    };

    more_message.sort_by(|l, r| {
        let left_time = NaiveDateTime::parse_from_str(&l.create_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        let right_time = NaiveDateTime::parse_from_str(&r.create_time, "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();
        if left_time > right_time {
            return Ordering::Greater;
        } else if left_time < right_time {
            return Ordering::Less;
        }
        return Ordering::Equal;
    });
    let group_message = group_item_by_time(more_message);

    let json = serde_json::to_string(&BaseChatValueBean {
        data: group_message,
    });

    Ok(json.unwrap())
}
